package com.xcity.db.entity;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.EnumMap;
import java.util.List;

import org.slf4j.Logger;

import com.xcity.game.buildv2.BuildV2;
import com.xcity.game.combat.CombatUtils;
import com.xcity.game.combat.attr.CombatAttribute;
import com.xcity.game.combat.attr.CombatAttributeType;
import com.xcity.game.combat.attr.response.CombatAttributeInfo;
import com.xcity.game.combat.calc.CombatAttributeCalculator;
import com.xcity.game.combat.calc.impl.EmployeeCombatAttributeCalculator;
import com.xcity.game.combat.template.CombatAttributeTemplate;
import com.xcity.game.combat.unit.CombatableBase;
import com.xcity.game.common.ConfirmOperation;
import com.xcity.game.conquests.Conquest;
import com.xcity.game.employee.EmployeeManager;
import com.xcity.game.employee.EmployeeQuality;
import com.xcity.game.employee.EmployeeService;
import com.xcity.game.employee.EmployeeUtils;
import com.xcity.game.employee.config.EmployeeServiceConfigure;
import com.xcity.game.employee.template.EmployeeBlessTemplate;
import com.xcity.game.employee.template.EmployeeQualityUpTemplate;
import com.xcity.game.employee.template.EmployeeStarUpTemplate;
import com.xcity.game.employee.template.EmployeeTemplate;
import com.xcity.game.equip.Equip;
import com.xcity.game.equip.EquipBrand;
import com.xcity.game.equip.EquipPosition;
import com.xcity.game.equip.EquipSuit;
import com.xcity.game.equip.Equipments;
import com.xcity.game.event.GameEvents;
import com.xcity.game.skill.SkillUtils;
import com.xcity.game.skill.v2.DefaultSkillV2;
import com.xcity.game.skill.v2.SkillManagerV2;
import com.xcity.pomelo.push.SyncPush;
import com.xcity.pomelo.push.sync.MapSync;
import com.xcity.pomelo.response.EquipmentBagResponse.Equipment;
import com.xcity.pomelo.response.EquipmentBagResponse.EquipmentSuit;
import com.xcity.pomelo.response.EquipmentBagResponse.EquipmentSuitEffect;
import com.xcity.util.ExpCalculator;
import com.xcity.util.IdUtils;

import naga.x.App;
import naga.x.game.template.TemplateService;
import naga.x.game.time.TimeUpdater;

public class Employee implements CombatableBase/*, EnhancedUnit*/ {

	protected long id;
	protected EmployeeTemplate template;
	protected int exp;
	protected int level;
	protected int qualityLvl; // 品级
	protected int starLvl; // 星级
	@Deprecated
	protected int energy; // 精力
	protected State state;
//	protected List<EmployeeSkill> skills;
	protected SkillManagerV2 skillManager;
//	protected float[] attributes; // 战斗属性成长值
	protected long[] equips; // 装备
	protected int[] blessExps;
	protected int[] blessLvls;
	protected Date createTime;
	protected float[] blessAtts;// 开光属性成长值

	protected CombatAttributeTemplate attributeTemplate;
	protected EmployeeManager vm;
	private int combatPower = -1; // 战斗力
	private List<CombatAttribute> combos; // 羁绊属性加成
	private CombatAttributeCalculator<Employee> calc = new EmployeeCombatAttributeCalculator(this);
	
	protected static final Logger LOG = EmployeeService.LOG;
	
	public static enum State {
		/** 空闲 */
		FREE,
		/** 建筑中 */
		DEFENSE,
		/** 驻守在占领建筑中 */
		CAPTURE,
		/** 战斗阵型中 */
		IN_FORMATION(false),
		;
		public final boolean enable; // 该状态是否有用（上阵不用检测状态）20170407
		State() {
			this(true);
		}
		State(boolean enable) {
			this.enable = enable;
		}
		public int codeOfOldVersion() {
			if (this == DEFENSE) {
				return 3;
			}
			if (this == CAPTURE) {
				return 7;
			}
			return 2;
		}
		public static State forCodeOfOldVersion(int oldCode) {
			if (oldCode == 3) {
				return DEFENSE;
			}
			if (oldCode == 7) {
				return CAPTURE;
			}
			return FREE;
		}
	}
	
//	public static enum State {
//		INIT_RECRUIT, // 待招聘(临时id) 0
//		PENDING_RECRUIT, // 待招聘(正式id) 1
//		FREE(true, null), // 空闲状态 2
//		DEFENSE, // 防守状态(建筑员工槽中) 3
//		@Deprecated
//		PRE_DEFENSE(true, "防守队"), // 预防守状态(即可派遣到建筑中) 4
//		@Deprecated
//		PRE_PVE(true, "谈判队"), // 可参加PVE 5
//		@Deprecated
//		PRE_ATTACK_BUILD(true, "掠夺队"), // 可攻击建筑 6
//		DEFENSE_OTHER_BUILD, // 驻守在其他玩家建筑中 7
//		;
//		public final boolean switchable; // 是否可在列表中手动切换状态
//		public final String name;
//		State() {
//			this(false, null);
//		}
//		State(boolean switchable, String name) {
//			this.switchable = switchable;
//			this.name = name;
//		}
//		public final int capacity(Player player) {
//			if (switchable) {
//				return Integer.MAX_VALUE;
//			}
//			return 0;
//		}
//		public final State[] getRelatedStates() {
//			if (this == PRE_DEFENSE || this == DEFENSE) {
//				return new State[] { PRE_DEFENSE, DEFENSE };
//			}
//			return new State[] { this };
//		}
//	}
	
	public Employee() {
//		if(blessAtts == null){
//			blessAtts = new float[CombatAttributeType.length()]; 
//		}
	}
	
	public Employee(EmployeeTemplate template, EmployeeManager vm, EmployeeServiceConfigure builder) {
		this.vm = vm;
		this.id = IdUtils.nextEmployeeId();
		this.template = template;
		this.exp = 0;
		this.level = 1;
		this.qualityLvl = 0;
		this.starLvl = 0;
		this.energy = template.getEnergy();
		this.state = State.FREE;
		this.blessExps = new int[]{0, 0, 0, 0};
		this.blessLvls = new int[]{1, 1, 1, 1};
//		this.attributes = new float[CombatAttributeType.length()];
		this.createTime = new Date(TimeUpdater.getInstance().now());
//		this.blessAtts = new float[CombatAttributeType.length()];
		this.doInit(builder);
	}
	
	public void doInit(EmployeeServiceConfigure builder) {
		SkillManagerV2 skillManager = new SkillManagerV2(this, SkillUtils.createActiveSkill(this), SkillUtils.createPassiveSkills(this));
		setSkillManager(skillManager);
		this.init();
	}
	
	public void init() {
		calc.calc();
	}
	
//	@Override
//	public float getSTR() {
//		return EmployeeUtils.getSTR(this);
//	}
//
//	@Override
//	public float getINT() {
//		return EmployeeUtils.getINT(this);
//	}
//
//	@Override
//	public float getAGI() {
//		return EmployeeUtils.getAGI(this);
//	}
//
//	@Override
//	public float getSPI() {
//		return EmployeeUtils.getSPI(this);
//	}
//
//	@Override
//	public float getSTA() {
//		return EmployeeUtils.getSTA(this);
//	}

	public float getAttributeValue(CombatAttributeType type) {
//		return CombatUtils.getAttributeValue(this, type);
		return calc.getValue(type);
	}

	@Override
	public float setAttributeValue(CombatAttributeType type, float value) {
		return 0;
	}
	
	@Override
	public long getId() {
		return id;
	}

	@Override
	public void setId(long id) {
		this.id = id;
	}

	@Override
	public String getName() {
		return template.getName();
	}
	
	@Override
	public byte getSex() {
		return template.getSex();
	}

	@Override
	public String getIcon() {
		return template.getIcon();
	}

	@Override
	public int getLevel() {
		return level;
	}

	@Override
	public void setLevel(int level) {
		this.level = level;
	}
	
	public int getQualityLvl() {
		return qualityLvl;
	}

	public void setQualityLvl(int qualityLvl) {
		this.qualityLvl = qualityLvl;
	}

	public EmployeeTemplate getTemplate() {
		return template;
	}

	public void setTemplate(EmployeeTemplate template) {
		this.template = template;
	}
	
	public int getExp() {
		return exp;
	}

	public void setExp(int exp) {
		this.exp = exp;
	}

	public int getStarLvl() {
		return starLvl;
	}

	public void setStarLvl(int starLvl) {
		this.starLvl = starLvl;
	}

	public int getEnergy() {
		return energy;
	}

	public void setEnergy(int energy) {
		this.energy = energy;
	}

	public State getState() {
		return state;
	}

	public void setState(State state) {
		setState(state, false);
	}
	
	public void setState(State state, boolean sync) {
		this.state = state;
		fireStateChanged(sync);
	}

	public Date getCreateTime() {
		return createTime;
	}

	public void setCreateTime(Date createTime) {
		this.createTime = createTime;
	}

	@Override
	public List<DefaultSkillV2> getSkills() {
		DefaultSkillV2 active = skillManager.getActive();
		return Arrays.asList(active);
	}
	
	public SkillManagerV2 getSkillManager() {
		return skillManager;
	}

	public void setSkillManager(SkillManagerV2 skillManager) {
		this.skillManager = skillManager;
		if (skillManager != null) {
			skillManager.setOwner(this);
		}
	}

//	public float[] getAttributes() {
//		return attributes;
//	}
//
//	public void setAttributes(float[] attributes) {
//		this.attributes = attributes;
//	}
//	
//	@Override
//	public float getEnhancedValue(CombatAttributeType type) {
//		int i = type.ordinal();
//		return i >= 0 && i < attributes.length ? attributes[i] : 0f;
//	}

	public long[] getEquips() {
		return equips;
	}

	public void setEquips(long[] equips) {
		this.equips = equips;
	}

	public int[] getBlessExps() {
		return blessExps == null ? (blessExps = new int[]{0, 0, 0, 0}) : blessExps;
	}

	public void setBlessExps(int[] blessExps) {
		this.blessExps = blessExps;
	}

	public int[] getBlessLvls() {
		return blessLvls == null ? (blessLvls = new int[]{1, 1, 1, 1}) : blessLvls;
	}

	public void setBlessLvls(int[] blessLvls) {
		this.blessLvls = blessLvls;
	}

	public EmployeeManager getVm() {
		return vm;
	}
	
	public void setVm(EmployeeManager vm) {
		this.vm = vm;
	}
	
	public long getOwnerId() {
		return vm.getOwner().getId();
	}
	
//	public float[] getBlessAtts() {
//		return blessAtts;
//	}
//	public void setBlessAtts(float[] blessAtts) {
//		this.blessAtts = blessAtts;
//	}
//	public float getBlessAttributeValue(CombatAttributeType type) {
//		int i = type.ordinal();
//		return i >= 0 && i < blessAtts.length ? blessAtts[i] : 0f;
//	}

	public int getMaxEnergy() {
		return template.getEnergy() + level - 1;
	}

//	public EmployeeSkill getSkillByGroup(int group) {
//		List<EmployeeSkill> skills = this.skills;
//		for (int i = 0; i < skills.size(); i++) {
//			EmployeeSkill skill = skills.get(i);
//			if (skill.getTemplate().getGroup() == group) {
//				return skill;
//			}
//		}
//		return null;
//	}
//	
//	public EmployeeSkill getSkillByType(byte type) {
//		for (int i = 0, size = skills != null ? skills.size() : 0; i < size; i++) {
//			EmployeeSkill skill = skills.get(i);
//			if (skill.getTemplate().getType() == type) {
//				return skill;
//			}
//		}
//		return null;
//	}
//	
//	public Float[] getSkillValues(int type) {
//		EmployeeSkill skill = getSkillByGroup(type);
//		return skill != null ? skill.getValue() : null;
//	}
//	
//	public float getSkillValue(int type, int index) {
//		EmployeeSkill skill = getSkillByGroup(type);
//		return skill != null ? skill.getValue(index) : 0f;
//	}
//	
//	public EmployeeSkill addSkill(EmployeeSkill skill) {
//		if (skills == null) {
//			skills = new ArrayList<>(2);
//		}
//		for (int i = 0; i < skills.size(); i++) {
//			EmployeeSkill old = skills.get(i);
//			if (old.getTemplate().getType() == skill.getTemplate().getType()) {
//				// replace
//				return skills.set(i, skill);
//			}
//		}
//		skills.add(skill);
//		return null;
//	}
	
	public boolean addExp(int val, String cause) {
		EmployeeQuality quality = getTemplate().getQuality();
		if (val <= 0 || level >= EmployeeUtils.getMaxLevel(quality)) {
			return false;
		}
		int oldExp = exp;
		exp += val;
		int oldLvl = level;
		level = EmployeeUtils.exp2Lvl(exp, quality);
		if (level > oldLvl) {
//			addEnergy(1, Cause.LEVEL_UP);
//			for (int i = 0, size = skills != null ? skills.size() : 0; i < size; i++) {
//				EmployeeSkill skill = skills.get(i);
//				skill.addLevel(level - oldLvl);
//			}
			App.getApp().getEventManager().addEvent(GameEvents.EVENT_EMPLOYEE_LEVEL_UP, vm.getOwner(), this, oldLvl);
			fireAttributesChanged(CombatAttributeType.MASK_FULL);
		}
		LOG.info("[EMPLOYEE ADDEXP]ID[{}]EMPLOYEE[{}={}]OLD[{}]NEW[{}]LVL[{}]CAUSE[{}]", vm.getOwner().getId(), id, getTemplate().getId(), oldExp, exp, level, cause);
		return true;
	}
	
	public boolean addBlessExp(int val, int slot, ExpCalculator blessCalc, List<EmployeeBlessTemplate> lvl2temp, String cause){
		//TODO
		if(blessExps == null){
			blessExps = new int[]{0, 0, 0, 0};
		}
		if(blessLvls == null){
			blessLvls = new int[]{1, 1, 1, 1};
		}
//		if(attributes == null){
//			attributes = new float[CombatAttributeType.length()];
//		}
		if(val <= 0 || blessLvls[slot] >= blessCalc.getMaxLevel()){
			return false;
		}
		int oldExp = blessExps[slot];
		blessExps[slot] += val;
		int oldLvl = blessLvls[slot];
		blessLvls[slot] = blessCalc.exp2Lvl(blessExps[slot]);
		if(blessLvls[slot] > oldLvl){
			int mask = 0;
			for(int i = oldLvl; i < blessLvls[slot]; i++){
				CombatAttribute[] vals = lvl2temp.get(i).getAttributes();//实际上真正等级是lvl-1
				for(int j = 0; j < vals.length; j++){
					CombatAttribute refer = vals[j];
					int offset = refer.getType().ordinal();
					if(refer.getValue() > 0){
//						blessAtts[offset] += refer.getValue();
						mask |= 1 << offset;
					}
				}
			}
			fireAttributesChanged(mask);
		}
		LOG.info("[EMPLOYEE_ADDBLESSEXP]ID[{}]EMPLOYEE[{}={}]OLD[{}]NEW[{}]OLDLVL[{}]NEWLVL[{}]CAUSE[{}]", vm.getOwner().getId(), id, getTemplate().getId(), oldExp, blessExps[slot], oldLvl, blessLvls[slot], cause);
		return true;
	}
	
	@Deprecated
	public boolean addEnergy(int val, String cause) {
		int maxVal;
		if (val <= 0 || energy >= (maxVal = getMaxEnergy()) || energy + val <= 0) {
			return false;
		}
		int oldVal = energy;
		energy += val;
		if (energy > maxVal) {
			energy = maxVal;
		}
		Player player = vm.getOwner();
		player.send(new MapSync(SyncPush.SYNC_EMPLOYEE_ENERGY, id, energy));
		LOG.info("[EMPLOYEE ADDENERGY]ID[{}]EMPLOYEE[{}={}]OLD[{}]NEW[{}]CAUSE[{}]", vm.getOwner().getId(), id, getTemplate().getId(), oldVal, energy, cause);
		return true;
	}
	
	@Deprecated
	public boolean decEnergy(int val, String cause) {
		if (val <= 0 || val > energy) {
			return false;
		}
		int oldVal = energy;
		energy -= val;
		Player player = vm.getOwner();
		player.send(new MapSync(SyncPush.SYNC_EMPLOYEE_ENERGY, id, energy));
		LOG.info("[EMPLOYEE DECENERGY]ID[{}]EMPLOYEE[{}={}]OLD[{}]NEW[{}]CAUSE[{}]", player.getId(), id, getTemplate().getId(), oldVal, energy, cause);
		return true;
	}
	
	public boolean hasEquipment() {
		long[] equips = getEquips();
		for (int i = 0, len = equips != null ? equips.length : 0; i < len; i++) {
			long eq = equips[i];
			if (eq != 0L/* && getVm().getOwner().getEquips().getEquip(eq) != null*/) {
				return true;
			}
		}
		return false;
	}
	
	public boolean hasEquipment(long id) {
		long[] equips = getEquips();
		for (int i = 0, len = equips != null ? equips.length : 0; i < len; i++) {
			long eq = equips[i];
			if (eq == id) {
				return true;
			}
		}
		return false;
	}
	
	public void equip(int pos, Equip equip) {
		if (pos >= 0 && pos < EquipPosition.MAX) {
			if (equips == null) {
				equips = new long[EquipPosition.MAX];
			}
			long oldEqId = equips[pos];
			Equip oldEq;
			if (oldEqId != 0 && (oldEq = getVm().getOwner().getEquips().getEquip(oldEqId)) != null) {
				oldEq.setState(Equip.State.IN_BAG, true);
			}
			equips[pos] = equip.getId();
			equip.setState(Equip.State.IN_EMPLOYEE, true);
			fireEquipmentChanged();
		}
	}
	
	public void unEquip(int pos) {
		if (pos >= 0 && pos < EquipPosition.MAX) {
			if (equips != null) {
				long id = equips[pos];
				Equip eq;
				if (id != 0 && (eq = getVm().getOwner().getEquips().getEquip(id)) != null) {
					eq.setState(Equip.State.IN_BAG, true);
				}
				equips[pos] = 0;
				fireEquipmentChanged();
			}
		}
	}
	
	public void unEquips(String cause) {
		for (int i = 0; i < EquipPosition.MAX; i++) {
			unEquip(i);
		}
		LOG.info("[EMPLOYEE UNEQUIP BATCH]ID[{}]EMPLOYEE[{}={}]CAUSE[{}]", getVm().getOwner().getId(), getId(), getTemplate().getId(), cause);
	}
	
	private void fireEquipmentChanged() {
		equipments = null;
		suits = null;
		fireAttributesChanged(CombatAttributeType.MASK_FULL);
	}
	
	/** 装备缓存 */
	private List<Equipment> equipments;
	public List<Equipment> getEquipments() {
		if (equipments != null) {
			return equipments;
		}
		long[] ids = getEquips();
		int len;
		if (ids == null || (len = ids.length) == 0) {
			return equipments = Collections.emptyList();
		}
		equipments = new ArrayList<Equipment>(len);
		Equipments equs = getVm().getOwner().getEquips();
		for (long id : ids) {
			Equip e = id != 0 ? equs.getEquip(id) : null;
			equipments.add(e != null ? new Equipment(e) : Equipment.EMPTY);
		}
		return equipments;
	}
	
	/** 套装效果缓存 */
	private List<EquipmentSuit> suits;
	public List<EquipmentSuit> getEquipSuits() {
		if (suits != null) {
			return suits;
		}
		long[] ids = getEquips();
		if (ids == null || ids.length == 0) {
			return suits = Collections.emptyList();
		}
		EnumMap<EquipBrand, List<Equip>> brand2equips = new EnumMap<>(EquipBrand.class);
		Equipments equs = getVm().getOwner().getEquips();
		for (long id : ids) {
			Equip e;
			if (id != 0 && (e = equs.getEquip(id)) != null) {
				EquipBrand brand = e.getTemplate().getBrand();
				if (brand == null || brand == EquipBrand.UNKNOWN) {
					continue;
				}
				List<Equip> list = brand2equips.get(brand);
				if (list == null) {
					list = new ArrayList<Equip>(4);
					brand2equips.put(brand, list);
				}
				list.add(e);
				if (list.size() >= EquipSuit.SUIT2.count) {
					if (suits == null) suits = new ArrayList<>(2);
					EquipmentSuitEffect eff = EquipmentSuit.find(suits, brand, EquipSuit.SUIT2);
					eff.active = ConfirmOperation.YES; // 会重复一次
					if (list.size() >= EquipSuit.SUIT4.count) {
						eff = EquipmentSuit.find(suits, brand, EquipSuit.SUIT4);
						eff.active = ConfirmOperation.YES;
					}
				}
			}
		}
		if (suits == null) {
			suits = Collections.emptyList();
		}
		return suits;
	}
	
	/**
	 * 品级成长
	 * @param val
	 * @param template
	 * @param cause
	 * @return
	 */
	public boolean addQualityLevel(int val, EmployeeQualityUpTemplate template, String cause) {
		int oldLvl = qualityLvl;
		qualityLvl += val;
//		if (attributes == null) {
//			attributes = new float[CombatAttributeType.length()];
//		}
		CombatAttribute[] growthVals = template.getAttributes();
		int mask = 0;
		for (int i = 0; i < growthVals.length; i++) {
			CombatAttribute refer = growthVals[i];
			int offset = refer.getType().ordinal();
//			attributes[offset] += refer.getValue();
			mask |= 1 << offset;
		}
		fireAttributesChanged(mask);
		LOG.info("[EMPLOYEE QUALITY LVLUP]ID[{}]EMPLOYEE[{}={}]OLD[{}]NEW[{}]CAUSE[{}]", getVm().getOwner().getId(), getId(), getTemplate().getId(), oldLvl, getQualityLvl(), cause);
		return true;
	}
	
	/**
	 * 星级成长
	 * @param val
	 * @param template
	 * @param cause
	 * @return
	 */
	public boolean addStarLevel(int val, EmployeeStarUpTemplate template, String cause) {
		int oldLvl = starLvl;
		starLvl += val;
//		if (attributes == null) {
//			attributes = new float[CombatAttributeType.length()];
//		}
		CombatAttribute[] growthVals = template.getAttributes();
		int mask = 0;
		for (int i = 0; i < growthVals.length; i++) {
			CombatAttribute refer = growthVals[i];
			int offset = refer.getType().ordinal();
//			attributes[offset] += refer.getValue();
			mask |= 1 << offset;
		}
		fireAttributesChanged(mask);
		LOG.info("[EMPLOYEE STAR LVLUP]ID[{}]EMPLOYEE[{}={}]OLD[{}]NEW[{}]CAUSE[{}]", getVm().getOwner().getId(), getId(), getTemplate().getId(), oldLvl, getStarLvl(), cause);
		return true;
	}
	
	/**
	 * 该员工是否培养过（升级、升品、升星）
	 * @return
	 */
	public boolean isTrained() {
//		if (exp > 0) {
//			return true;
//		}
//		for (int i = attributes != null ? attributes.length - 1 : -1; i >= 0; i--) {
//			if (attributes[i] > 0f) {
//				return true;
//			}
//		}
//		return false;
		if (exp > 0 || qualityLvl > 0 || starLvl > 0) {
			return true;
		}
		SkillManagerV2 skm = getSkillManager();
		DefaultSkillV2 sk = skm.getActive();
		if (sk.getLevel() > 1) {
			return true;
		}
		List<DefaultSkillV2> sks = skm.getPassives();
		for (int i = 0; i < sks.size(); i++) {
			sk = sks.get(i);
			if (sk.getLevel() > 1) {
				return true;
			}
		}
		return false;
	}
	
	private BuildV2 building; // cache
	public BuildV2 getBuilding() {
		if (building == null) {
			if (state == State.DEFENSE) {
				List<BuildV2> buildings = getVm().getOwner().getBuildings2().getBuildings();
				for (int i = 0; i < buildings.size(); i++) {
					BuildV2 b = buildings.get(i);
					if (b.hasEmployee(id)) {
						building = b;
						return b;
					}
				}
			} else if (state == State.CAPTURE) {
				Conquest c = getVm().getOwner().getConquests().findByEmployee(this);
				BuildV2 b = c != null ? c.ref2() : null;
				building = b;
				return b;
			}
		}
		return building;
	}
	
	private void fireStateChanged(boolean sync) {
		building = null;
		if (state == null || !state.enable) {
			state = State.FREE;
		}
		if (sync) {
			getVm().getOwner().send(new MapSync(SyncPush.SYNC_EMPLOYEE_STATE, getId(), state.codeOfOldVersion()));
		}
	}
	
	@Override
	public int getCombatPower() {
		if (combatPower == -1) {
			combatPower = CombatUtils.calcCombatPower(this);
		}
		return combatPower;
	}
	
	@Override
	public void fireAttributesChanged(int mask) {
		if (mask != 0) {
			Player player = getVm().getOwner();
			calc.calc();
			CombatAttributeType[] types = CombatAttributeType.vals;
			int len = types.length;
			List<CombatAttributeInfo> changes = new ArrayList<>(len);
			for (CombatAttributeType type : types) {
				if ((mask >> type.ordinal() & 1) != 0) { // 只同步发生变化的属性值
					changes.add(new CombatAttributeInfo(type, getAttributeValue(type)));
				}
			}
			player.send(new MapSync(SyncPush.SYNC_COMBAT_ATTRIBUTES, getId(), changes));
			
			int val = CombatUtils.calcCombatPower(this);
			if (combatPower != val) {
				combatPower = val;
				player.send(new MapSync(SyncPush.SYNC_EMPLOYEE_COMBAT_POWER, getId(), val));
				App.getApp().getEventManager().addEvent(GameEvents.EVENT_EMPLOYEE_COMBAT_POWER_CHANGED, this);
			}
		}
	}

	public List<CombatAttribute> getCombos() {
		return combos != null ? combos : (combos = EmployeeUtils.initCombos(this));
	}

	public void setCombos(List<CombatAttribute> combos) {
		this.combos = combos;
	}
	
	public void reborn() {
		exp = 0;
		level = 1;
		qualityLvl = 0;
		starLvl = 0;
//		float[] attrs = getAttributes();
//		if (attrs != null) {
//			Arrays.fill(attrs, 0f);
//		}
		SkillManagerV2 skm = getSkillManager();
		DefaultSkillV2 sk = skm.getActive();
		sk.reset();
		List<DefaultSkillV2> sks = skm.getPassives();
		for (int i = 0; i < sks.size(); i++) {
			sk = sks.get(i);
			sk.reset();
		}
		fireAttributesChanged(CombatAttributeType.MASK_FULL);
	}
	
	public CombatAttributeTemplate getAttributeTemplate() {
		return attributeTemplate != null ? attributeTemplate: (attributeTemplate = App.getApp().getServiceManager().get(TemplateService.class).get(CombatAttributeTemplate.class, getTemplate().getId()));
	}
	
}
